package utils

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"
)

var commitLogFormatFields = []string{
	"%H",  // commit hash
	"%s",  // subject
	"%B",  // raw body (subject + body)
	"%an", // author name
	"%ae", // author email
	"%aI", // author date, strict ISO 8601 format
	"%cn", // committer name
	"%ce", // committer email
	"%cI", // committer date, strict ISO 8601 format
	"%P",  // parent hashes
}

const fieldDelimiterGitFormatString = "%x1f"

type GitCommit struct {
	Id        string
	Subject   string
	Body      string
	Author    *CommitAuthor
	Committer *CommitAuthor
	ParentIds []string
}

type CommitAuthor struct {
	Name     string
	Email    string
	Date     time.Time
	Timezone string
}

// GetCommit returns a single GitCommit
func GetCommit(ctx context.Context, revision string, envs []string) (*GitCommit, error) {
	cmd, err := GitLogCommand(ctx, []string{revision}, envs, "--max-count=1")
	if err != nil {
		return nil, err
	}

	logParser := NewLogParser(cmd)
	if ok := logParser.Parse(); !ok {
		return nil, fmt.Errorf("revision not exist")
	}

	return logParser.Commit(), nil
}

func GitLogCommand(ctx context.Context, revisions []string, envs []string, extraArgs ...string) (Commander, error) {
	formatFlag := "--pretty=format:" + strings.Join(commitLogFormatFields, fieldDelimiterGitFormatString)

	flags := []string{
		"log",
		"-z",
		formatFlag,
	}

	flags = append(flags, extraArgs...)
	flags = append(flags, revisions...)

	cmd := exec.Command("git", flags...)

	command, err := NewCommand(ctx, cmd, nil, nil, nil, envs...)
	if err != nil {
		return nil, err
	}

	return command, nil
}
